home *** CD-ROM | disk | FTP | other *** search
/ Scene 96 / Scene 96 International Edition (Zyklop Software) (Disc 2) (1997).iso / misc / coding / pump_src / phong.c < prev    next >
C/C++ Source or Header  |  1995-10-26  |  14KB  |  450 lines

  1. //──────────────────────────────────────────────────────────────────────────
  2. // Implementación del engine Phong/EnvMapping, Yann/Iguana
  3. //──────────────────────────────────────────────────────────────────────────
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <sincos.h>
  8. #include <vga.h>
  9. #include "phong.h"
  10. #include "ph_fill.h"
  11.  
  12. extern int tracing;
  13. #define TRACE(r,g,b) do { if (tracing) VGA_PutColor(0,r,g,b); } while(0)
  14.  
  15. void *frame_buffer_adr = (void *)0xA0000;
  16.  
  17. #define MAX_OBJECTS 5
  18. #define VERY_CLOSE 10
  19. #define BACKFACE_CULL
  20.  
  21. struct O3DHeader {
  22.         UWORD m_num_vertices;
  23.         UWORD m_num_triangles;
  24. };
  25.  
  26. static struct CGlobalTri {
  27.         UWORD m_num_obj;        // En qué objeto está el triangulo
  28.         UWORD m_num_tri;        // Qué triángulo dentro del objeto
  29.         UWORD m_distance;       // Distancia a la que está el tri.
  30.         struct CGlobalTri *m_next;     // Link
  31. };
  32.  
  33. static struct CObject {
  34.         struct CPoint      *m_vertices;
  35.         struct CNormal     *m_normals;
  36.         struct CTriangle   *m_triangles;
  37.         struct CPoint      *m_xvertices;
  38.         struct CPoint2D    *m_proj_vertices;
  39.         struct CNormal     *m_xnormals;
  40.         UWORD m_num_obj;                // Identificador de objeto **//**
  41.         UWORD m_num_vertices, m_num_triangles;
  42.         BOOL m_all_ok;
  43.         BOOL m_active;
  44. } s_objects[MAX_OBJECTS];
  45.  
  46. static int s_num_objects = 0;           // Cuántos son -^
  47.  
  48. static struct CGlobalTri *s_list = 0;          // Lista global de triángulos
  49. static struct CGlobalTri *s_pool = 0, *s_next = 0;     // Pool para no hacer mallocs
  50.  
  51.  
  52. static struct CGlobalTri *GetTri(void) {       // Acceso al pool
  53.         return s_next++;
  54. }
  55.  
  56. static void RestartPool(void) {   // Inicializar la pool
  57.         s_next = s_pool;
  58. }
  59.  
  60. void PH_SetMode13BufferAdr(void *p) {
  61.     frame_buffer_adr = p;
  62. }
  63.  
  64. void *PH_GetMode13BufferAdr(void) {
  65.     return frame_buffer_adr;
  66. }
  67.  
  68. static struct CObject *NewObject(void) {
  69.     struct CObject *p = s_objects + s_num_objects;
  70.     if (s_num_objects == MAX_OBJECTS) {
  71.         puts("ORRRROOOOORRRRRRRRR!!!!!!!!!!!!!");
  72.         exit(-1);
  73.     }
  74.     p->m_num_obj = s_num_objects++;
  75.     return p;
  76. }
  77.  
  78. static void ReserveMem(struct CObject *p) {
  79.     p->m_all_ok = FALSE;
  80.  
  81.     p->m_xvertices = calloc(p->m_num_vertices, sizeof(struct CPoint));
  82.     if (!p->m_xvertices)
  83.         return;
  84.     p->m_xnormals = calloc(p->m_num_vertices, sizeof(struct CNormal));
  85.     if (!p->m_xnormals) {
  86.         free(p->m_xvertices);
  87.         return;
  88.     }
  89.     p->m_proj_vertices = calloc(p->m_num_vertices, sizeof(struct CPoint2D));
  90.     if (!p->m_proj_vertices) {
  91.         free(p->m_xvertices);
  92.         free(p->m_xnormals);
  93.         return;
  94.     }
  95.     p->m_vertices = calloc(p->m_num_vertices, sizeof(struct CPoint));
  96.     if (!p->m_vertices) {
  97.         free(p->m_xvertices);
  98.         free(p->m_xnormals);
  99.         free(p->m_proj_vertices);
  100.         return;
  101.     }
  102.     p->m_normals = calloc(p->m_num_vertices, sizeof(struct CNormal));
  103.     if (!p->m_normals) {
  104.         free(p->m_xvertices);
  105.         free(p->m_xnormals);
  106.         free(p->m_proj_vertices);
  107.         free(p->m_vertices);
  108.         return;
  109.     }
  110.     p->m_triangles = calloc(p->m_num_triangles, sizeof(struct CTriangle));
  111.     if (!p->m_triangles) {
  112.         free(p->m_xvertices);
  113.         free(p->m_xnormals);
  114.         free(p->m_proj_vertices);
  115.         free(p->m_vertices);
  116.         free(p->m_normals);
  117.         return;
  118.     }
  119.     p->m_all_ok = TRUE;
  120. }
  121.  
  122. HANDLE PH_BuildObj(BYTE *file_like_buffer) {
  123.     struct O3DHeader hdr;
  124.     struct CObject *p = NewObject();
  125.     char *q = (char *)file_like_buffer;
  126.     p->m_all_ok = FALSE;
  127.  
  128.     memcpy(&hdr, q, sizeof(struct O3DHeader));
  129.     q += sizeof(struct O3DHeader);
  130.  
  131.     // Reservar memoria
  132.     p->m_num_vertices = hdr.m_num_vertices;
  133.     p->m_num_triangles = hdr.m_num_triangles;
  134.     ReserveMem(p);
  135.     if (!p->m_all_ok) {
  136.         return 0;
  137.     }
  138.  
  139.     // Leer los datos
  140.     memcpy(p->m_vertices, q, p->m_num_vertices * sizeof(struct CPoint));
  141.     q += p->m_num_vertices * sizeof(struct CPoint);
  142.     memcpy(p->m_normals, q, p->m_num_vertices * sizeof(struct CNormal));
  143.     q += p->m_num_vertices * sizeof(struct CNormal);
  144.     memcpy(p->m_triangles, q, p->m_num_triangles * sizeof(struct CTriangle));
  145.     q += p->m_num_triangles * sizeof(struct CTriangle);
  146.     p->m_all_ok = TRUE;
  147.     p->m_active = TRUE;
  148.     return p - s_objects + 1;
  149. }
  150.  
  151. void PH_DestroyObj(HANDLE h) {
  152.     struct CObject *p = s_objects + h + 1;
  153.  
  154.     if (!p->m_all_ok)
  155.         return;
  156.  
  157.     if (p->m_xvertices)        free(p->m_xvertices);
  158.     if (p->m_xnormals)         free(p->m_xnormals);
  159.     if (p->m_vertices)         free(p->m_vertices);
  160.     if (p->m_normals)          free(p->m_normals);
  161.     if (p->m_triangles)        free(p->m_triangles);
  162.     if (p->m_proj_vertices)    free(p->m_proj_vertices);
  163.  
  164.     s_num_objects--;            // Llevar la cuenta (para automatizar más
  165.                                 // tarde algunas cosillas)
  166. }
  167.  
  168. int PH_StartEngine(void) {
  169.     // Se supone que ya se han construido todos los objetos.
  170.     // Vamos a reservar la memoria que hace falta para todo el render
  171.     int i;
  172.     UWORD total_tris = 0;
  173.  
  174.     for (i = 0; i < s_num_objects; i++) {
  175.         total_tris += s_objects[i].m_num_triangles;
  176.     }
  177.  
  178.     if (!total_tris)
  179.         return TRUE;    // No hay objetos!
  180.  
  181.     s_pool = calloc(total_tris, sizeof(struct CGlobalTri));
  182.     if (!s_pool)
  183.         return 0;       // No hay memoria
  184.     RestartPool();
  185.     return 1;
  186. }
  187.  
  188. void PH_EndEngine(void) {
  189.     free(s_pool);
  190. }
  191.  
  192. static void ProjectVertices(struct CObject *pobj) {
  193.     int i;
  194.     struct CPoint *p = pobj->m_xvertices;
  195.     struct CPoint2D *q = pobj->m_proj_vertices;
  196.  
  197.     for (i = 0; i < pobj->m_num_vertices; i++, p++, q++) {
  198.         if (p->z < VERY_CLOSE) {
  199.             q->x = 0;
  200.             q->y = 0;
  201.             continue;
  202.         }
  203.  
  204.         q->x = (((DWORD)p->x << 8) / p->z) + 160;
  205.         q->y = (((DWORD)p->y << 8) / p->z) + 100;
  206.     }                 
  207. }
  208.  
  209. static void DumpPolygons(struct CObject *p) {
  210.     int i;
  211.     struct CTriangle *pt = p->m_triangles;
  212.     struct CPoint *pp1, *pp2, *pp3;
  213.  
  214.     // Añadir todos los triángulos del objeto actual a la lista global,
  215.     // haciendo un sencillo clipping accept/reject
  216.     for (i = 0; i < p->m_num_triangles; i++, pt++) {
  217.         struct CGlobalTri *pgtri;
  218.         pp1 = p->m_xvertices + pt->p1;
  219.         pp2 = p->m_xvertices + pt->p2;
  220.         pp3 = p->m_xvertices + pt->p3;
  221.         if (pp1->z < VERY_CLOSE || pp2->z < VERY_CLOSE || pp3->z < VERY_CLOSE)
  222.             continue;
  223.  
  224.         pgtri = GetTri();
  225.  
  226.         pgtri->m_num_obj = p->m_num_obj;
  227.         pgtri->m_num_tri = i;
  228.         pgtri->m_distance = pp1->z + pp2->z + pp3->z;
  229.         pgtri->m_next = s_list;
  230.         s_list = pgtri;
  231.     }
  232. }
  233.  
  234. void PH_DrawFrame(void) {
  235.     int i;
  236.     struct CGlobalTri *trav;
  237.  
  238.     // Comenzamos un render
  239.     RestartPool();
  240.     s_list = NULL;
  241.  
  242.     TRACE(32,32,0);
  243.     // Llamar a ProjectVertices y DumpPolygons para todos los polígonos
  244.     for (i = 0; i < s_num_objects; i++) {
  245.         if (s_objects[i].m_active) {
  246.             ProjectVertices(s_objects + i);
  247.             DumpPolygons(s_objects + i);
  248.         }
  249.     }
  250.  
  251.     // Ordenar los triángulos de todos los objetos
  252.     TRACE(16,16,16);
  253.     SortTris();
  254.  
  255.     // Dibujarlos todos con ph_fill, haciendo backface-culling
  256.     for (trav = s_list; trav; trav = trav->m_next) {
  257.         BYTE z_val[3];
  258.         struct CObject *pobj = s_objects + trav->m_num_obj;
  259.         struct CTriangle *pt = pobj->m_triangles + trav->m_num_tri;
  260.  
  261.         TRACE(0,0,16);
  262.  
  263.         ex1 = pobj->m_proj_vertices[pt->p1].x;
  264.         ey1 = pobj->m_proj_vertices[pt->p1].y;
  265.         ex2 = pobj->m_proj_vertices[pt->p2].x;
  266.         ey2 = pobj->m_proj_vertices[pt->p2].y;
  267.         ex3 = pobj->m_proj_vertices[pt->p3].x;
  268.         ey3 = pobj->m_proj_vertices[pt->p3].y;
  269.  
  270. #ifdef BACKFACE_CULL
  271.         if ((ex2-ex1)*(ey3-ey2)-(ey2-ey1)*(ex3-ex2) < 0) {
  272.             continue;
  273.         }
  274. #endif
  275.  
  276.         z_val[0] = pobj->m_xnormals[pt->p1].z;
  277.         z_val[1] = pobj->m_xnormals[pt->p2].z;
  278.         z_val[2] = pobj->m_xnormals[pt->p3].z;
  279.         if (z_val[0] <= 0 && z_val[1] <= 0 && z_val[2] <= 0) {
  280.             u1 = v1 = u2 = v2 = u3 = v3 = 0;
  281.         } else {
  282.             u1 = ((WORD)pobj->m_xnormals[pt->p1].x << 8) + 0x8000;
  283.             v1 = ((WORD)pobj->m_xnormals[pt->p1].y << 8) + 0x8000;
  284.             u2 = ((WORD)pobj->m_xnormals[pt->p2].x << 8) + 0x8000;
  285.             v2 = ((WORD)pobj->m_xnormals[pt->p2].y << 8) + 0x8000;
  286.             u3 = ((WORD)pobj->m_xnormals[pt->p3].x << 8) + 0x8000;
  287.             v3 = ((WORD)pobj->m_xnormals[pt->p3].y << 8) + 0x8000;
  288.         }
  289.         TRACE(40,40,40);
  290.         phong_fill();
  291.     }
  292. }
  293.  
  294. /////////////////////////////////////////////////////////////////////////////
  295. // Ordena la lista s_list, utilizando el método RADIX-SORT con raíz 16,
  296. // por lo que hacen falta 4 pasadas
  297. /////////////////////////////////////////////////////////////////////////////
  298. #if 1
  299. #define RADIX 16
  300. #define PASSES 4
  301. #define EXTRACT(num, pass) \
  302.         ((num >> (pass << 2)) & (RADIX-1))
  303. #else
  304. #define RADIX 256
  305. #define PASSES 2
  306. #define EXTRACT(num, pass) \
  307.         ((num >> (pass << 3)) & (RADIX-1))
  308. #endif
  309. static void SortTris(void) {
  310.     WORD i, j;
  311.     struct CGlobalTri *heads[RADIX], *head, **tails[RADIX], **tail,
  312.             *trav, *temp_next;
  313.  
  314.     // Ordenar la lista de triángulos global
  315.     head = s_list;
  316.     for (i = 0; i < PASSES; i++) {
  317.         // Inicializar tails
  318.         for (j = 0; j < RADIX; j++) {
  319.             tails[j] = heads + j;
  320.         }
  321.  
  322.         // Recorrer la lista principal y separar en RADIX listas
  323.         for (trav = head; trav; trav = temp_next) {
  324.             int k;
  325.  
  326.             temp_next = trav->m_next;
  327.             k = EXTRACT(trav->m_distance, i);
  328.             *tails[k] = trav;
  329.             tails[k] = &trav->m_next;
  330.         }
  331.  
  332.         // Terminar las listas
  333.         for (j = 0; j < RADIX; j++) {
  334.             *tails[j] = NULL;
  335.         }
  336.  
  337.         // Añadir las listas a la lista principal
  338.         head = NULL;
  339.         tail = &head;
  340.         //for (j = 0; j < RADIX; j++) {         // Orden creciente
  341.         for (j = RADIX - 1; j >= 0; j--) {      // Orden decreciente
  342.             if (heads[j]) {
  343.                 // Añadir la lista número 'j' al final
  344.                 *tail = heads[j];
  345.                 tail = tails[j];
  346.             }
  347.         }
  348.     }
  349.     s_list = head;
  350. }
  351.  
  352. void PH_XFormVertices(HANDLE h, UWORD theta, UWORD phi, WORD x, WORD y, WORD z) {
  353.     int i;
  354.     DWORD cos_theta = Cos(theta);
  355.     DWORD sin_theta = -Sin(theta);
  356.     DWORD cos_phi = Cos(phi);
  357.     DWORD sin_phi = Sin(phi);
  358.     DWORD sinphi_sintheta = FPMult(sin_phi, sin_theta);
  359.     DWORD sinphi_costheta = FPMult(sin_phi, cos_theta);
  360.     DWORD cosphi_sintheta = FPMult(cos_phi, sin_theta);
  361.     DWORD cosphi_costheta = FPMult(cos_phi, cos_theta);
  362.     struct CPoint *p;
  363.     struct CPoint *q;
  364.     struct CObject *pobj = s_objects + h - 1;
  365.  
  366.     for (i = 0, p = pobj->m_vertices, q = pobj->m_xvertices ;
  367.          i < pobj->m_num_vertices;
  368.          i++, p++, q++) {
  369. /*
  370.         q->x = x + FPMult(p->x, cos_theta) + FPMult(p->z, sin_theta);
  371.         q->y = y + p->y;
  372.         q->z = z + FPMult(p->z, cos_theta) - FPMult(p->x, sin_theta);
  373. */
  374.         q->x = x + FPMult(p->x, cos_theta) + FPMult(p->z, sin_theta);
  375.         q->y = y    - FPMult(p->x, sinphi_sintheta)
  376.                     + FPMult(p->y, cos_phi)
  377.                     + FPMult(p->z, sinphi_costheta);
  378.         q->z = z    - FPMult(p->x, cosphi_sintheta)
  379.                     - FPMult(p->y, sin_phi)
  380.                     + FPMult(p->z, cosphi_costheta);
  381.     }
  382. }
  383.  
  384. #define NONE 8
  385. static int repr[] =
  386.     { 2, 3, NONE, NONE, NONE, 4, NONE, 5, 1, NONE, 0, NONE, NONE, NONE, 7, 6 };
  387.  
  388. static BYTE u_repr[] =
  389.     { 127, 90, 0, -90, -127, -90, 0, 90,        0}; // Last is for NONE
  390.  
  391. static BYTE v_repr[] =
  392.     { 0, 90, 127, 90, 0, -90, -127, -90,        0};
  393.  
  394. void PH_XFormNormals(HANDLE h, WORD theta, UWORD phi, WORD alpha) {
  395.     int i;
  396.     DWORD cos_theta, sin_theta, cos_phi, sin_phi;
  397.     DWORD sinphi_sintheta;
  398.     DWORD sinphi_costheta;
  399.     DWORD cosphi_sintheta;
  400.     DWORD cosphi_costheta;
  401.     struct CObject *pobj = s_objects + h - 1;
  402.     struct CNormal *r = pobj->m_normals;
  403.     struct CNormal *s = pobj->m_xnormals;
  404.  
  405.     theta += alpha;
  406.     cos_theta = Cos(theta);
  407.     sin_theta = -Sin(theta);
  408.     cos_phi = Cos(phi);
  409.     sin_phi = Sin(phi);
  410.     sinphi_sintheta = FPMult(sin_phi, sin_theta);
  411.     sinphi_costheta = FPMult(sin_phi, cos_theta);
  412.     cosphi_sintheta = FPMult(cos_phi, sin_theta);
  413.     cosphi_costheta = FPMult(cos_phi, cos_theta);
  414.  
  415.     // Xform normals
  416.     for (i = 0; i < pobj->m_num_vertices; i++) {
  417. /*
  418.         s->x = FPMult(cos_sum, r->x) + FPMult(sin_sum, r->z);
  419.         s->y = r->y;
  420.         s->z = FPMult(cos_sum, r->z) - FPMult(sin_sum, r->x);
  421. */
  422.         s->x =     FPMult(r->x, cos_theta) + FPMult(r->z, sin_theta);
  423.         s->y =      - FPMult(r->x, sinphi_sintheta)
  424.                     + FPMult(r->y, cos_phi)
  425.                     + FPMult(r->z, sinphi_costheta);
  426.         s->z =      - FPMult(r->x, cosphi_sintheta)
  427.                     - FPMult(r->y, sin_phi)
  428.                     + FPMult(r->z, cosphi_costheta);
  429.         if (s->z <= 0) {
  430.             WORD u, v, code;
  431.             u = s->x; v = s->y;
  432.  
  433.             code = (((UWORD)(v - (u<<1))) >> 15) << 3
  434.                 |  (((UWORD)(u + (v<<1))) >> 15) << 2
  435.                 |  (((UWORD)((v<<1) - u)) >> 15) << 1
  436.                 |  (((UWORD)(v + (u<<1))) >> 15);
  437.             s->x = u_repr[repr[code]];
  438.             s->y = v_repr[repr[code]];
  439.         }
  440.  
  441.         s++, r++;
  442.     }
  443. }
  444.  
  445. void PH_ActivateObj(HANDLE h, int active) {
  446.     struct CObject *pobj = s_objects + h - 1;
  447.     pobj->m_active = active;
  448. }
  449.  
  450.